package vn.edu.saigontech.ncms.service.impl;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.List;

import org.hibernate.Criteria;
import org.hibernate.criterion.MatchMode;
import org.hibernate.criterion.Order;
import org.hibernate.criterion.Projections;
import org.hibernate.criterion.Restrictions;

import vn.edu.saigontech.ncms.model.info.Student;
import vn.edu.saigontech.ncms.model.info.StudentType;
import vn.edu.saigontech.ncms.model.program.Level;
import vn.edu.saigontech.ncms.model.program.Program;
import vn.edu.saigontech.ncms.model.result.PlacementTest;
import vn.edu.saigontech.ncms.model.user.User;
import vn.edu.saigontech.ncms.service.PlacementTestService;
import vn.edu.saigontech.ncms.util.Checker;
import vn.edu.saigontech.ncms.util.DateUtil;

@SuppressWarnings("unchecked")
public class PlacementTestServiceImpl extends
		HibernateGenericService<PlacementTest, Long> implements
		PlacementTestService {

	public PlacementTest findByStudentId(Long studentId) {
		Criteria criteria = this.createCriteria();
		criteria.createCriteria("student")
				.add(Restrictions.eq("id", studentId));
		return (PlacementTest) criteria.uniqueResult();
	}

	public boolean deleteByStudentId(Long studentId) {
		return super.deleteById(this.findByStudentId(studentId).getId());
	}

	@Override
	public int countInMonth(int month, int year) {
		Criteria criteria = this.createCriteria();
		criteria.add(Restrictions.between("date", DateUtil.getStartDateOfMonth(
				month, year), DateUtil.getEndDateOfMonth(month, year)));
		criteria.setProjection(Projections.rowCount());
		return (Integer) criteria.uniqueResult();
	}

	public PlacementTest createBlankPlacementTest() {
		Program program = new Program();
		Level level = new Level();
		level.setProgram(program);
		Student student = new Student();
		student.setType(new StudentType());
		student.setConsultant(new User());
		student.setProgram(new Program());
		PlacementTest placementTest = new PlacementTest();
		placementTest.setStudent(student);
		placementTest.setLevel(level);
		return placementTest;
	}

	@Override
	public PlacementTest findByReceiptNo(String receiptNo) {
		Criteria criteria = this.createCriteria();
		criteria.add(Restrictions.eq("receiptNo", receiptNo));
		return (PlacementTest) criteria.uniqueResult();
	}

	@Override
	public Collection<PlacementTest> find(PlacementTest placementTest) {
		Criteria criteria = this.createCriteria();
		Criteria studentCriteria = criteria.createCriteria("student");

		if (!Checker.isEmpty(placementTest.getStudent().getFirstName())) {
			studentCriteria.add(Restrictions.ilike("firstName", placementTest
					.getStudent().getFirstName(), MatchMode.ANYWHERE));
		}
		if (!Checker.isEmpty(placementTest.getStudent().getLastName())) {
			studentCriteria.add(Restrictions.ilike("lastName", placementTest
					.getStudent().getLastName(), MatchMode.ANYWHERE));
		}
		if (!Checker.isNull(placementTest.getFromTestDate())
				&& !Checker.isNull(placementTest.getToTestDate())) {
			criteria.add(Restrictions.between("date", placementTest
					.getFromTestDate(), placementTest.getToTestDate()));
		} else if (!Checker.isNull(placementTest.getDate())) {
			criteria.add(Restrictions.eq("date", placementTest.getDate()));
		}
		if(Checker.isNotNull(placementTest.getPlacementShift())) {
			criteria.add(Restrictions.eq("placementShift", placementTest.getPlacementShift()));
		}
		if (!Checker.isNull(placementTest.getStudent().getType().getId())) {
			studentCriteria.createCriteria("type").add(
					Restrictions.eq("id", placementTest.getStudent().getType()
							.getId()));
		}
		if (!Checker.isNull(placementTest.getLevel().getId())) {
			System.out.println("Level ID: " + placementTest.getLevel().getId());
			criteria.createCriteria("level").add(
					Restrictions.eq("id", placementTest.getLevel().getId()));
		}
		if (!Checker.isNull(placementTest.getStudent().getFromConsultedDate())
				&& !Checker.isNull(placementTest.getStudent()
						.getToConsultedDate())) {
			studentCriteria.add(Restrictions.between("consultedDate",
					placementTest.getStudent().getFromConsultedDate(),
					placementTest.getStudent().getToConsultedDate()));
		} else if (!Checker.isNull(placementTest.getStudent()
				.getConsultedDate())) {
			studentCriteria.add(Restrictions.eq("consultedDate", placementTest
					.getStudent().getConsultedDate()));
		}
		if (!Checker.isNull(placementTest.getStudent().getProgram().getId())) {
			studentCriteria.createCriteria("program").add(
					Restrictions.eq("id", placementTest.getStudent()
							.getProgram().getId()));
		}
		if (!Checker.isNull(placementTest.getStudent().getConsultant().getId())) {
			studentCriteria.createCriteria("consultant").add(
					Restrictions.eq("id", placementTest.getStudent()
							.getConsultant().getId()));
		}
		studentCriteria.addOrder(Order.asc("firstName"));
		return criteria.list();
	}

	@Override
	public Collection<PlacementTest> findByMonth(int month, int year) {
		Date loDate = DateUtil.getStartDateOfMonth(month, year);
		Date hiDate = DateUtil.getEndDateOfMonth(month, year);
		Criteria criteria = this.createCriteria();
		criteria.add(Restrictions.between("date", loDate, hiDate));
		criteria.addOrder(Order.asc("date"));
		criteria.addOrder(Order.asc("receiptNo"));

		List<PlacementTest> result = new ArrayList<PlacementTest>();
		for (PlacementTest each : (Collection<PlacementTest>) criteria.list()) {
			if (!Checker.isEmpty(each.getReceiptNo())) {
				result.add(each);
			}
		}
		Comparator<PlacementTest> comp = new Comparator<PlacementTest>() {
			@Override
			public int compare(PlacementTest o1, PlacementTest o2) {
				return o1.getReceiptNo().compareTo(o2.getReceiptNo());
			}
		};
		Collections.sort(result, comp);
		return result;
	}
	
	@Override
	public List<PlacementTest> findByDate(Date fromDate, Date toDate) {
		Criteria criteria = this.createCriteria();
		if(!Checker.isNull(fromDate)) {
			criteria.add(Restrictions.ge("date", fromDate));
		}
		if(!Checker.isNull(toDate)) {
			criteria.add(Restrictions.le("date", toDate));
		}
		criteria.addOrder(Order.asc("id"));
		return criteria.list();
	}
}